package com.mdd.front.service.pay.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mdd.common.constant.GlobalConstant;
import com.mdd.common.entity.code.CouponCode;
import com.mdd.common.entity.coupon.UserCoupon;
import com.mdd.common.entity.goods.Goods;
import com.mdd.common.entity.goods.GoodsSpecification;
import com.mdd.common.entity.goods.OrderGoods;
import com.mdd.common.entity.order.Order;
import com.mdd.common.entity.recharge.RechargeOrder;
import com.mdd.common.entity.relevancy.OrderBuyRelevancy;
import com.mdd.common.entity.user.UserAuth;
import com.mdd.common.enums.OrderPayStatusEnum;
import com.mdd.common.enums.OrderPlayTypeEnum;
import com.mdd.common.enums.OrderStatusEnum;
import com.mdd.common.enums.PaymentEnum;
import com.mdd.common.exception.OperateException;
import com.mdd.common.mapper.album.AlbumMapper;
import com.mdd.common.mapper.coupon.CouponCodeMapper;
import com.mdd.common.mapper.coupon.UserCouponMapper;
import com.mdd.common.mapper.order.OrderMapper;
import com.mdd.common.mapper.recharge.RechargeOrderMapper;
import com.mdd.common.mapper.relevancy.OrderBuyRelevancyMapper;
import com.mdd.common.mapper.specification.GoodsSpecificationMapper;
import com.mdd.common.mapper.user.UserAuthMapper;
import com.mdd.common.utils.*;
import com.mdd.front.LikeFrontThreadLocal;
import com.mdd.front.service.IUserService;
import com.mdd.front.service.goods.impl.GoodsServiceImpl;
import com.mdd.front.service.goods.impl.OrderGoodsServiceImpl;
import com.mdd.front.service.order.IOrderService;
import com.mdd.front.service.pay.IBalancePayService;
import com.mdd.front.service.pay.ICBCService;
import com.mdd.front.service.pay.IWxpayService;
import com.mdd.front.service.recharge.IRechargeService;
import com.mdd.front.validate.BalancePayValidate;
import com.mdd.front.validate.PaymentValidate;
import com.mdd.front.vo.user.UserInfoVo;
import com.mdd.front.vo.wxpay.WxPayCreateOrderRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class WxpayServiceImpl implements IWxpayService {

    @Resource
    private IOrderService iOrderService;

    @Resource
    private RechargeOrderMapper rechargeOrderMapper;
    @Resource
    private IBalancePayService iBalancePayService;
    @Resource
    private IRechargeService iRechargeService;
    @Resource
    private IUserService userService;

    @Resource
    private ICBCService icbcService;

    @Resource
    private UserAuthMapper userAuthMapper;

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    @Value("${wx.pay.order-notify-url}")
    private String orderNotifyUrl;
	@Qualifier("orderMapper")
	@Autowired
	private OrderMapper orderMapper;
	@Qualifier("orderBuyRelevancyMapper")
	@Autowired
	private OrderBuyRelevancyMapper orderBuyRelevancyMapper;
	@Autowired
	private GoodsServiceImpl goodsServiceImpl;
	@Autowired
	private OrderGoodsServiceImpl orderGoodsServiceImpl;
	@Qualifier("goodsSpecificationMapper")
	@Autowired
	private GoodsSpecificationMapper goodsSpecificationMapper;
	@Qualifier("userCouponMapper")
	@Autowired
	private UserCouponMapper userCouponMapper;
    @Qualifier("couponCodeMapper")
    @Autowired
    private CouponCodeMapper couponCodeMapper;
    @Qualifier("albumMapper")
    @Autowired
    private AlbumMapper albumMapper;

    @Override
    public WxPayUnifiedOrderV3Result.JsapiResult createOrder(WxPayCreateOrderRequest request) throws WxPayException {
        // 订单编号
        String orderSn = "";
        // 订单状态
        Integer orderStatus = 0;
        // 订单金额
        BigDecimal orderAmount = BigDecimal.ZERO;

        switch (request.getScene()){
            case "order":
                Order order = this.iOrderService.getById(Long.valueOf(request.getOrderId()), LikeFrontThreadLocal.getUserId());
                orderSn = order.getSn();
                orderStatus = order.getOrderStatus();
                orderAmount = order.getOrderAmount();
                Assert.notNull(order, "订单不存在");
                break;
            case "recharge":
                RechargeOrder rechargeOrder = rechargeOrderMapper.selectOne(new QueryWrapper<RechargeOrder>()
                        .eq("id", request.getOrderId())
                        .eq("order_status", OrderStatusEnum.WAIT_PAY.getStatus())
                        .eq("pay_status", OrderPayStatusEnum.WAIT_PAY.getStatus())
                        .eq("user_id", LikeFrontThreadLocal.getUserId())
                        .last("limit 1"));
                orderSn = rechargeOrder.getOrderSn();
                orderStatus = rechargeOrder.getPayStatus();
                orderAmount = rechargeOrder.getOrderAmount();
                Assert.notNull(rechargeOrder, "订单不存在");
                break;
            default:
                throw new OperateException("不支持当前订单类型");
        }
        log.info("微信创建预支付订单请求对象:{}", request);
        Assert.isTrue(orderStatus != null && orderStatus == OrderStatusEnum.WAIT_PAY.getStatus(), "订单非待支付状态，不能创建支付单");
        UserInfoVo userInfoVo = userService.info(LikeFrontThreadLocal.getUserId());
        Integer client = 0;
        if ("mp_channel".equals(request.getPayChannel())){
            client = 1;
        }
        if ("oa_channel".equals(request.getPayChannel())){
            client = 2;
        }
        log.info("支付渠道：{}", request.getPayChannel());
        UserAuth userAuth = userAuthMapper.selectOne(new QueryWrapper<UserAuth>()
                .select("id,openid")
                .eq("user_id", LikeFrontThreadLocal.getUserId())
                .eq("client", client)
                .last("limit 1"));
        String openid = userAuth.getOpenid();
        Assert.isTrue(userInfoVo.getIsBindMnp() && openid != null, "当前用户未绑定微信");
        Long expireTime = TimeUtil.timestamp() * 1000 + 1800000L;
        String timeExpire = format.format(expireTime) + "+08:00";
        WxPayService wxPayService = WxPayServiceUtils.wxPayService(request.getPayChannel());
        // null 指针
//        wxPayService.closeOrderV3(orderSn);
        if ("order".equals(request.getScene())){
            Order order = this.iOrderService.updateSn(request.getOrderId(), request.getPayChannel());
            orderSn = order.getSn();
        }
        if ("recharge".equals(request.getScene())){
            RechargeOrder rechargeOrder = iRechargeService.updateSn(request.getOrderId(), request.getPayChannel());
            orderSn = rechargeOrder.getOrderSn();
        }
        WxPayUnifiedOrderV3Request wxPayUnifiedOrderV3Request = new WxPayUnifiedOrderV3Request();
        wxPayUnifiedOrderV3Request.setOutTradeNo(orderSn);
        wxPayUnifiedOrderV3Request.setNotifyUrl(UrlUtil.localDomain(orderNotifyUrl));
        wxPayUnifiedOrderV3Request.setDescription("上门预约-支付订单");
        wxPayUnifiedOrderV3Request.setTimeExpire(timeExpire);
        WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
        amount.setTotal(AmountUtil.yuan2Fen(orderAmount.toPlainString()));
        amount.setCurrency("CNY");
        wxPayUnifiedOrderV3Request.setAmount(amount);
        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
        payer.setOpenid(openid);
        wxPayUnifiedOrderV3Request.setPayer(payer);
        log.info("微信创建预支付订单请求对象{}", wxPayUnifiedOrderV3Request);
        WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, wxPayUnifiedOrderV3Request);
        Assert.notNull(jsapiResult, "不支持当前支付渠道！");
        log.info("微信创建预支付订单结果:{}", jsapiResult);
        return jsapiResult;
    }

    @Override
    public Object prePay(PaymentValidate paymentValidate) throws WxPayException {

        // 更新支付方式
        switch (paymentValidate.getScene()){
            case "order":
                iOrderService.updateOrderPayWay(paymentValidate.getOrderId(), paymentValidate.getPayWay());
                break;
            case "recharge":
                Map<String, String> config = ConfigUtil.get("recharge");
                String rechargeOpen = config.getOrDefault("rechargeOpen", "0");
                Assert.isTrue(0 != Integer.parseInt(rechargeOpen),"系统暂未开启充值功能！");
                iRechargeService.updateRechargePayWay(paymentValidate.getOrderId(), paymentValidate.getPayWay());
                break;
        }
        // 组装支付参数
        WxPayCreateOrderRequest request = new WxPayCreateOrderRequest();
        request.setOrderId(paymentValidate.getOrderId());
        request.setPayChannel(paymentValidate.getPayChannel());
        request.setScene(paymentValidate.getScene());
        paymentValidate.setPayWay(PaymentEnum.ALI_PAY.getCode());
        Integer orderId = paymentValidate.getOrderId();
        Order order = orderMapper.selectById(orderId);
        if(Objects.nonNull(order) && order.getOrderAmount().compareTo(new BigDecimal("0")) == 0 && StringUtil.isEmpty(paymentValidate.getCode())){
            String[] split = order.getCouponId().substring(1, order.getCouponId().length() - 1).replaceAll(" ", "").split(",");
            List<Long> collect1 = Arrays.stream(split).map(Long::parseLong).collect(Collectors.toList());
            LambdaQueryWrapper<UserCoupon> queryWrapper = new LambdaQueryWrapper<>();
            collect1.forEach(couponId -> {
                queryWrapper.eq(UserCoupon::getCouponId, couponId);
                queryWrapper.eq(UserCoupon::getUserId, order.getUserId());
                queryWrapper.eq(UserCoupon::getIsDelete, GlobalConstant.NOT_DELETE);
                UserCoupon userCoupon = userCouponMapper.selectOne(queryWrapper);
                userCoupon.setIsUsed(1);
                userCoupon.setUpdateTime(TimeUtil.timestamp());
                userCouponMapper.updateById(userCoupon);
            });
            String sn = order.getSn();
            log.info("{} 订单交易成功", sn);
            // 获取ICBC的订单id， 用于进行退款
            order.setTransactionId("不能退款");
            //更新订单状态
            order.setOrderStatus(OrderStatusEnum.RESERVE.getStatus());
            order.setPayStatus(OrderPayStatusEnum.PAY.getStatus());
            order.setPayTime(TimeUtil.timestamp());
            order.setPayWay(OrderPlayTypeEnum.WECHAT_PAY.getType());
            order.setUpdateTime(TimeUtil.timestamp());
            OrderGoods byOrderId = orderGoodsServiceImpl.getByOrderId(order.getId());
            Goods goods = goodsServiceImpl.getEntityById(byOrderId.getGoodsId());
            if(goods.getIsManualDispatch().equals(GlobalConstant.DELETE)){
                order.setOrderStatus(OrderStatusEnum.SERVICING.getStatus());
            }
            // 如果是团购订单支付成功，则进行修改团购订单表的数据
            if(order.getIsBuy() == 1) {
                log.info("该订单是团购订单: {}", order);
                OrderBuyRelevancy orderBuyRelevancy = orderBuyRelevancyMapper.selectOne(new LambdaQueryWrapper<OrderBuyRelevancy>()
                        .eq(OrderBuyRelevancy::getIsDelete, GlobalConstant.NOT_DELETE)
                        .like(OrderBuyRelevancy::getUnpaidOrderIds, order.getId()));
                String s = StringUtil.trimStr(orderBuyRelevancy.getUnpaidOrderIds(), order.getId() + "");
                orderBuyRelevancy.setUnpaidOrderIds(s);
                if(orderBuyRelevancy.getInitiatorOrderId() != order.getId().intValue()) {
                    if(StringUtil.isEmpty(orderBuyRelevancy.getRelevancyOrderIds())) {
                        orderBuyRelevancy.setRelevancyOrderIds("" + order.getId());
                    } else {
                        orderBuyRelevancy.setRelevancyOrderIds(orderBuyRelevancy.getRelevancyOrderIds()+","+order.getId());
                    }
                }
                if(StringUtil.isNotEmpty(orderBuyRelevancy.getRelevancyOrderIds()) && orderBuyRelevancy.getRelevancyOrderIds().split(",").length+1 == goods.getBuyPeopleNum()) {
                    orderBuyRelevancy.setBuyStatus(GlobalConstant.DELETE); // 设置团购成功
                }
                orderBuyRelevancyMapper.updateById(orderBuyRelevancy);
            }
            orderMapper.updateById(order);
            return "支付成功！";
        } else if(StringUtil.isNotEmpty(paymentValidate.getCode())) {
            // 修改code的状态
            LambdaQueryWrapper<CouponCode> couponCodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
            couponCodeLambdaQueryWrapper.eq(CouponCode::getCouponCode, paymentValidate.getCode());
            couponCodeLambdaQueryWrapper.eq(CouponCode::getIsUse, 0);
            CouponCode couponCode = couponCodeMapper.selectOne(couponCodeLambdaQueryWrapper);
            if(Objects.isNull(couponCode)) {
                throw new OperateException("免费拉新码不存在或已使用");
            }
            couponCode.setIsUse(1);
            couponCodeMapper.updateById(couponCode);
            // 删除图片
            albumMapper.deleteById(couponCode.getImageId());
            order.setTransactionId("不能退款");
            //更新订单状态
            order.setOrderStatus(OrderStatusEnum.RESERVE.getStatus());
            order.setPayStatus(OrderPayStatusEnum.PAY.getStatus());
            order.setPayTime(TimeUtil.timestamp());
            order.setPayWay(OrderPlayTypeEnum.WECHAT_PAY.getType());
            order.setUpdateTime(TimeUtil.timestamp());
            OrderGoods byOrderId = orderGoodsServiceImpl.getByOrderId(order.getId());
            Goods goods = goodsServiceImpl.getEntityById(byOrderId.getGoodsId());
            Goods goods1 = goodsServiceImpl.getEntityById(goodsSpecificationMapper.selectOne(new LambdaQueryWrapper<GoodsSpecification>()
                    .eq(GoodsSpecification::getIsDelete, GlobalConstant.NOT_DELETE)
                    .eq(GoodsSpecification::getGoodsSpecificationId, goods.getId())).getGoodsId());
            if(goods1.getIsManualDispatch().equals(GlobalConstant.DELETE)){
                order.setOrderStatus(OrderStatusEnum.SERVICING.getStatus());
            }
            orderMapper.updateById(order);
            RedisUtil.del(paymentValidate.getCode());
            return "支付成功！";
        }
        switch (paymentValidate.getPayWay()){
            case 1:
                return this.createOrder(request);
            case 2:
                Assert.isTrue(!"recharge".equals(paymentValidate.getScene()),"充值订单不支持余额支付！");
                BalancePayValidate balancePayValidate = new BalancePayValidate();
                balancePayValidate.setOrderId(paymentValidate.getOrderId());
                iBalancePayService.balance2PayOrder(balancePayValidate, LikeFrontThreadLocal.getUserId());
                return "支付成功！";
            case 3:
                return icbcService.getICBCPayParam(request);
        }
        return "支付失败";
    }

}
